<!DOCTYPE html>
<html class="no-js" lang="zh">
  <head>
<meta charset="utf-8">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="alternate" href="https://www.desgard.com" hreflang="pt-BR">
<link href="http://gmpg.org/xfn/11" rel="profile">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="theme-color" content="#005344">
<title>Guardia · 瓜地</title>
<meta name="google-site-verification" content="zS1dSn20XtA4FJYEOQLXqI0boxZdMnJ2g3beje-cl20">
<meta name="description" content="DGPopUpViewController---卡片式弹出窗口">
<meta name="keywords" content="">
<!-- Social: Facebook / Open Graph -->
<meta property="og:url" content="https://www.desgard.com/The-Card-Interface-For-Signing-Up/">
<meta property="og:title" content="       The Card Interface For Signing Up | Gua  ">
<meta property="og:description" content="DGPopUpViewController---卡片式弹出窗口">
<meta property="og:site_name" content="Desgard_Duan">
<meta property="og:locale" content="pt_BR">
<meta property="og:type" content="website">
<meta property="og:author" content="https://www.facebook.com/desgard.duan">
<meta property="og:image" content="https://www.desgard.com">
<!-- Social: Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@nandomoreirame">
<meta name="twitter:domain" content="https://www.desgard.com">
<meta name="twitter:title" content="       The Card Interface For Signing Up | Gua  ">
<meta name="twitter:description" content="DGPopUpViewController---卡片式弹出窗口">
<meta name="twitter:image:src" content="https://www.desgard.com">
<!-- Favicons -->
<link rel="apple-touch-icon" sizes="114x114" href="https://www.desgard.com/assets/ico/apple-touch-icon-114-516f4e19976b9e4dbb77ad9b576831fe.png">
<link rel="apple-touch-icon" sizes="72x72" href="https://www.desgard.com/assets/ico/apple-touch-icon-72-5409b2df229305703caf583d86c845ab.png">
<link rel="apple-touch-icon" href="https://www.desgard.com/assets/ico/apple-touch-icon-57-aa873e019cf659e0d4e6a0b5bb9f379d.png">
<link rel="shortcut icon" href="https://www.desgard.com/assets/ico/favicon-4298be3d3fbe23e18d65bded9d930899.png">
<!-- rel prev and next -->
<!-- Canonical link tag -->
<link rel="canonical" href="https://www.desgard.com/The-Card-Interface-For-Signing-Up/">
<link rel="alternate" type="application/rss+xml" title="Gua" href="https://www.desgard.com/feed.xml">
<link rel="stylesheet" href="/assets/main-0b7b828712f4c43b75bba4861c907bb1.css">
<script src="/assets/modernizr-custom-cb807611a3e262b2eac59444cbab74d6.js" data-cfasync="false"></script>
<script src="/assets/js/jquery-3.1.js"></script>
<script src="/assets/js/jquery.rotate.js"></script>
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "Website",
  "publisher": "www.desgard.com",
  "url": "http://www.desgard.com/",
  "description": "瓜地"
}
</script>
<script type="text/javascript">
  var disqus_shortname = 'desgard',
      baseurl          = '';
</script>
<!--
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-52446115-1']);
_gaq.push(['_trackPageview']);
(function() {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>-->
<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "//hm.baidu.com/hm.js?c5a8123bc51782a3083a631ed9ff50e4";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
      tex2jax: {
        inlineMath: [ ['$','$'] ],
        displayMath: [ ['$$','$$'] ],
        processEscapes: true
      }
    });
  </script>
  </head>
  <body class="post-template single">
    <header class="header">
  <div class="container">
    <h1><a href="/"><strong>desgard</strong>.com</a></h1>
    <nav class="navbar">
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="#!" data-modal="modalSearch"><i class="fa fa-search"></i></a></li>
        <li><a href="/comment " target="_blank"><i class="fa fa-comments"></i></a></li>
        <li><a href="/feed.xml" target="_blank"><i class="fa fa-feed"></i></a></li>
      </ul>
    </nav>
  </div>
</header>
    <main class="wrapper container" itemprop="mainContentOfPage" itemscope="itemscope" itemtype="http://schema.org/Blog">
      <article class="post" itemscope="itemscope" itemtype="http://schema.org/BlogPosting" itemprop="blogPost">
  <header class="post-header">
    <h1>The Card Interface For Signing Up</h1>
    <div class="post-meta">
      <time datetime="2015-10-13">
        <i class="fa fa-calendar-o"></i> <time datetime="2016-06-18"> 2016-06-18
      </time>
      <span>
        <i class="fa fa-comments"></i> <a href="#container">Comment me!</a>
      </span>
      <span>
<!--
-->
      </span>
    </div>
  </header>
  <p>Apple公司在WWDC 2016前后带来了10个重大更新，其中重中之重可谓是iOS 10的更新了。iOS 10被称作iOS 7之后迎来的最大升级，在所有的革新中，无论在通知中心的UI修改，还是各处的3D Touch弹出层，都能看到<code>卡片式设计</code>的影子。笔者不是设计师，但是以一个iOS开发者的角度来看，iOS的扁平化设计风格，逐渐正在往在Google I/O 2014提出的<code>卡片式设计</code>靠拢。（关于更多的<code>卡片式设计</code>资料可查看<a href="http://www.androidpolice.com/2014/06/11/exclusive-quantum-paper-and-googles-upcoming-effort-to-make-consistent-ui-simple/?utm_source=tuicool">这里</a>）。</p>
<p><img src="http://7xwh85.com1.z0.glb.clouddn.com/2016-06-18-img_0.jpg" alt="" /></p>
<p>处此大势之下，我也跟风来搞一波。首先先感谢原型图的作者<code>Sarah</code>，虽然我不是Dribbble的Pro用户，无法在您的作品上留言，但之后我会及时的联系你。以下就是原型图的效果了：</p>
<p><img src="http://7xwh85.com1.z0.glb.clouddn.com/2016-06-18-img_1.gif" alt="" /></p>
<h2 id="section">动画分析</h2>
<p>观察全部特效，我们发现了以下步骤</p>
<ul>
  <li>弹出卡片弹出窗口</li>
  <li>自定义<code>UITextField</code>填写进度动画</li>
  <li>卡片缩小至消失</li>
  <li>弹出logo动画片尾</li>
</ul>
<p>其中我们忽略掉一个效果，就是在原型图中，触摸键移动到NEXT按钮上的动效。因为在手机上，我们不可能持续在屏幕上滑动手指，而是采用轻按的方式。想必设计师当时忘记了使用场景，当做web来设计的。</p>
<p>一番动画分析之后，我们逐步击破。</p>
<h2 id="section-1">动画拆解</h2>
<h3 id="section-2">对于弹出层的构建</h3>
<p>笔者在实现之前，对于这个弹出的感觉就是在View上面附加一层View进行实现。我在<a href="https://github.com/vsouza/awesome-ios">awesome-ios</a>搜索了其他其他关于Popup View实现的方式，在主流的<a href="https://github.com/psy2k/NMPopUpView">NMPopUpView</a>、<a href="https://github.com/carsonperrotti/CNPPopupController">CNPPopup</a>等都是使用了ViewController来实现，虽然现在还没有明确这样做的好处，我觉的可能是减少了当前视图的负担。因为在弹出层中，有许多需要与触控手势的控件，所以对于View的负担过重。我们规划一下文件结构：</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="err">├──</span> <span class="no">DGPopUpViewController</span>
<span class="err">│  </span> <span class="err">├──</span> <span class="no">DGPopUpView</span><span class="o">.</span><span class="n">h</span>
<span class="err">│  </span> <span class="err">├──</span> <span class="no">DGPopUpView</span><span class="o">.</span><span class="n">m</span>
<span class="err">│  </span> <span class="err">├──</span> <span class="no">DGPopUpViewController</span><span class="o">.</span><span class="n">h</span>
<span class="err">│  </span> <span class="err">├──</span> <span class="no">DGPopUpViewController</span><span class="o">.</span><span class="n">m</span>
<span class="err">│  </span> <span class="err">├──</span> <span class="no">DGPopUpViewLoginButton</span><span class="o">.</span><span class="n">h</span>
<span class="err">│  </span> <span class="err">├──</span> <span class="no">DGPopUpViewLoginButton</span><span class="o">.</span><span class="n">m</span>
<span class="err">│  </span> <span class="err">├──</span> <span class="no">DGPopUpViewTextView</span><span class="o">.</span><span class="n">h</span>
<span class="err">│  </span> <span class="err">└──</span> <span class="no">DGPopUpViewTextView</span><span class="o">.</span><span class="n">m</span></code></pre></div>
<p><img src="http://7xwh85.com1.z0.glb.clouddn.com/2016-06-18-img_2.jpg" alt="" /></p>
<p>结构一目了然，<code>ViewController</code>持有<code>PopUpView</code>，<code>PopUpView</code>中带有其他的自定义控件。我们写一个对外接口，来将这层<code>ViewController</code>的视图显示在当前视图上，但是其控制器还要保持原本的控制器。另外要注意的是，在添加背景色的时候，我们用到了<code>UIColor</code>的<code>colorWithAlphaComponent</code>方法，具体的作用是对当前颜色具有透明状态。当然我们使用更改<code>alpha</code>也可修改透明状态，但是对View的修改，会影响到该View的子视图。</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1">#pragma mark - Override</span>
<span class="c1">#define DGPopUpViewBackgroundColor [[UIColor colorWithRed: 245 / 255.f green: 245 / 255.f blue: 245 / 255.f alpha: 1] colorWithAlphaComponent: 0.8]</span>
<span class="o">-</span> <span class="p">(</span><span class="n">instancetype</span><span class="p">)</span> <span class="n">init</span> <span class="p">{</span>
    <span class="n">isOpen</span> <span class="o">=</span> <span class="no">YES</span><span class="p">;</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">view</span><span class="o">.</span><span class="n">backgroundColor</span> <span class="o">=</span> <span class="no">DGPopUpViewBackgroundColor</span><span class="p">;</span>
    <span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">view</span> <span class="ss">addSubview</span><span class="p">:</span> <span class="nb">self</span><span class="o">.</span><span class="n">popUpCloseButton</span><span class="o">]</span><span class="p">;</span>
    <span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">view</span> <span class="ss">addSubview</span><span class="p">:</span> <span class="nb">self</span><span class="o">.</span><span class="n">popUpView</span><span class="o">]</span><span class="p">;</span>
    <span class="sr">//</span> <span class="err">尾部动画通知实现</span>
    <span class="o">[[</span><span class="no">NSNotificationCenter</span> <span class="n">defaultCenter</span><span class="o">]</span> <span class="ss">addObserver</span><span class="p">:</span> <span class="nb">self</span>
                                             <span class="ss">selector</span><span class="p">:</span> <span class="vi">@selector</span><span class="p">(</span><span class="n">endAnimation</span><span class="p">)</span>
                                                 <span class="nb">name</span><span class="p">:</span> <span class="err">@</span><span class="s2">&quot;end_animation&quot;</span>
                                               <span class="ss">object</span><span class="p">:</span> <span class="kp">nil</span><span class="o">]</span><span class="p">;</span>
    <span class="sr">//</span> <span class="err">尾部动画调试</span>
    <span class="sr">//</span> <span class="o">[</span><span class="nb">self</span> <span class="n">endAnimation</span><span class="o">]</span><span class="p">;</span>
    <span class="k">return</span> <span class="nb">self</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">#pragma mark - Add SubView</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span> <span class="ss">showInView</span><span class="p">:</span> <span class="p">(</span><span class="no">UIView</span> <span class="o">*</span><span class="p">)</span><span class="n">aView</span> <span class="ss">animated</span><span class="p">:</span> <span class="p">(</span><span class="no">BOOL</span><span class="p">)</span><span class="n">animated</span> <span class="p">{</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">view</span><span class="o">.</span><span class="n">center</span> <span class="o">=</span> <span class="n">aView</span><span class="o">.</span><span class="n">center</span><span class="p">;</span>
    <span class="o">[</span><span class="n">aView</span> <span class="ss">addSubview</span><span class="p">:</span> <span class="nb">self</span><span class="o">.</span><span class="n">view</span><span class="o">]</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">animated</span><span class="p">)</span> <span class="p">{</span>
        <span class="o">[</span><span class="nb">self</span> <span class="n">showAnimation</span><span class="o">]</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>写完入口方法之后，我们需要做一些处理。例如，在弹出层弹出后，若点击非<code>PopUpView</code>部分，即可将<code>PopUpView</code>退出的方法即相关动画。另外，还需要构建弹出动画、尾部的logo动画。</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1">#pragma mark - Removew SubView</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span> <span class="n">removeAnimation</span> <span class="p">{</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">popUpView</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="no">CGAffineTransformMakeScale</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="o">[</span><span class="no">UIView</span> <span class="ss">animateWithDuration</span><span class="p">:</span> <span class="mi">0</span><span class="o">.</span><span class="mi">6</span>
                          <span class="ss">delay</span><span class="p">:</span> <span class="mi">0</span>
                        <span class="ss">options</span><span class="p">:</span> <span class="no">UIViewAnimationOptionCurveEaseInOut</span>
                     <span class="ss">animations</span><span class="p">:</span> <span class="o">^</span><span class="p">{</span>
                         <span class="nb">self</span><span class="o">.</span><span class="n">popUpView</span><span class="o">.</span><span class="n">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                     <span class="p">}</span>
                     <span class="ss">completion</span><span class="p">:</span> <span class="o">^</span><span class="p">(</span><span class="no">BOOL</span> <span class="n">finished</span><span class="p">)</span> <span class="p">{</span>
                         <span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">view</span> <span class="n">removeFromSuperview</span><span class="o">]</span><span class="p">;</span>
                     <span class="p">}</span><span class="o">]</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span> <span class="n">endAnimation</span> <span class="p">{</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">endView</span> <span class="o">=</span> <span class="o">[[</span><span class="no">UIImageView</span> <span class="n">alloc</span><span class="o">]</span> <span class="ss">initWithImage</span><span class="p">:</span> <span class="o">[</span><span class="no">UIImage</span> <span class="ss">imageNamed</span><span class="p">:</span> <span class="err">@</span><span class="s2">&quot;end_logo&quot;</span><span class="o">]]</span><span class="p">;</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">endView</span><span class="o">.</span><span class="n">center</span> <span class="o">=</span> <span class="nb">self</span><span class="o">.</span><span class="n">view</span><span class="o">.</span><span class="n">center</span><span class="p">;</span>
    <span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">view</span> <span class="ss">addSubview</span><span class="p">:</span> <span class="nb">self</span><span class="o">.</span><span class="n">endView</span><span class="o">]</span><span class="p">;</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">endView</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="no">CGAffineTransformMakeScale</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="o">[</span><span class="no">UIView</span> <span class="ss">animateWithDuration</span><span class="p">:</span> <span class="mi">1</span><span class="o">.</span><span class="mi">4</span>
                          <span class="ss">delay</span><span class="p">:</span> <span class="mi">0</span>
                        <span class="ss">options</span><span class="p">:</span> <span class="no">UIViewAnimationOptionCurveEaseInOut</span>
                     <span class="ss">animations</span><span class="p">:</span> <span class="o">^</span><span class="p">{</span>
                         <span class="nb">self</span><span class="o">.</span><span class="n">endView</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="no">CGAffineTransformMakeScale</span><span class="p">(</span><span class="mi">0</span><span class="o">.</span><span class="mi">6</span><span class="p">,</span> <span class="mi">0</span><span class="o">.</span><span class="mi">6</span><span class="p">);</span>
                     <span class="p">}</span>
                     <span class="ss">completion</span><span class="p">:</span> <span class="o">^</span><span class="p">(</span><span class="no">BOOL</span> <span class="n">finished</span><span class="p">)</span> <span class="p">{</span>
                     <span class="p">}</span><span class="o">]</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">#pragma mark - Animation</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span> <span class="n">showAnimation</span> <span class="p">{</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">view</span><span class="o">.</span><span class="n">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="o">.</span><span class="mi">0</span><span class="p">;</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">popUpView</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="no">CGAffineTransformMakeScale</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="o">[</span><span class="no">UIView</span> <span class="ss">animateWithDuration</span><span class="p">:</span> <span class="mi">0</span><span class="o">.</span><span class="mi">25</span>
                     <span class="ss">animations</span><span class="p">:</span> <span class="o">^</span><span class="p">{</span>
                         <span class="nb">self</span><span class="o">.</span><span class="n">view</span><span class="o">.</span><span class="n">alpha</span> <span class="o">=</span> <span class="mi">1</span><span class="o">.</span><span class="mi">0</span><span class="p">;</span>
                     <span class="p">}</span>
                     <span class="ss">completion</span><span class="p">:</span> <span class="o">^</span><span class="p">(</span><span class="no">BOOL</span> <span class="n">finished</span><span class="p">)</span> <span class="p">{</span>
                         <span class="o">[</span><span class="nb">self</span> <span class="n">showPopUpView</span><span class="o">]</span><span class="p">;</span>
                     <span class="p">}</span><span class="o">]</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span> <span class="n">showPopUpView</span> <span class="p">{</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">popUpView</span><span class="o">.</span><span class="n">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="o">.</span><span class="mi">5</span><span class="p">;</span>
    <span class="o">[</span><span class="no">UIView</span> <span class="ss">animateWithDuration</span><span class="p">:</span> <span class="mi">0</span><span class="o">.</span><span class="mi">8</span>
                          <span class="ss">delay</span><span class="p">:</span> <span class="mi">0</span>
                        <span class="ss">options</span><span class="p">:</span> <span class="no">UIViewAnimationOptionCurveEaseOut</span>
                     <span class="ss">animations</span><span class="p">:</span> <span class="o">^</span><span class="p">{</span>
                         <span class="nb">self</span><span class="o">.</span><span class="n">popUpView</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="no">CGAffineTransformMakeScale</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
                         <span class="nb">self</span><span class="o">.</span><span class="n">popUpView</span><span class="o">.</span><span class="n">alpha</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
                     <span class="p">}</span>
                     <span class="ss">completion</span><span class="p">:</span> <span class="o">^</span><span class="p">(</span><span class="no">BOOL</span> <span class="n">finished</span><span class="p">)</span> <span class="p">{</span>
                     <span class="p">}</span><span class="o">]</span><span class="p">;</span>
<span class="p">}</span></code></pre></div>
<h3 id="section-3">弹出层</h3>
<p>在弹出层View中，我们需要做的就是在上面增加控件。弹出层需要持有的控件有三个：标题Label、自定义TextField、按钮Button。另外，需要他自身需要处理点击按钮正常退出的动画。这种弹出层退出方式与在控制器中的退出方式很显然响应者不同。在用户主动请求退出的过程中，用户主要是以控制器View作为交互对象，而点击Next按钮后的退出时与弹出层View为交互对象。这样写能让我们的代码更清晰，可读性加强。</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1">#pragma mark - Close Animation</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span> <span class="n">closeAnimation</span> <span class="p">{</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="no">CGAffineTransformMakeScale</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="o">[</span><span class="no">UIView</span> <span class="ss">animateWithDuration</span><span class="p">:</span> <span class="mi">0</span><span class="o">.</span><span class="mi">6</span>
                          <span class="ss">delay</span><span class="p">:</span> <span class="mi">0</span><span class="o">.</span><span class="mi">3</span>
                        <span class="ss">options</span><span class="p">:</span> <span class="no">UIViewAnimationOptionCurveEaseInOut</span>
                     <span class="ss">animations</span><span class="p">:</span> <span class="o">^</span><span class="p">{</span>
                         <span class="nb">self</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="no">CGAffineTransformMakeScale</span><span class="p">(</span><span class="mi">0</span><span class="o">.</span><span class="mo">01</span><span class="p">,</span> <span class="mi">0</span><span class="o">.</span><span class="mo">01</span><span class="p">);</span>
                         <span class="nb">self</span><span class="o">.</span><span class="n">superview</span><span class="o">.</span><span class="n">alpha</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
                     <span class="p">}</span>
                     <span class="ss">completion</span><span class="p">:</span> <span class="o">^</span><span class="p">(</span><span class="no">BOOL</span> <span class="n">finished</span><span class="p">)</span> <span class="p">{</span>
                         <span class="o">[[</span><span class="no">NSNotificationCenter</span> <span class="n">defaultCenter</span><span class="o">]</span> <span class="ss">postNotificationName</span><span class="p">:</span> <span class="err">@</span><span class="s2">&quot;end_animation&quot;</span> <span class="ss">object</span><span class="p">:</span> <span class="kp">nil</span><span class="o">]</span><span class="p">;</span>
                         <span class="o">[</span><span class="nb">self</span> <span class="n">removeFromSuperview</span><span class="o">]</span><span class="p">;</span>
                     <span class="p">}</span><span class="o">]</span><span class="p">;</span>
<span class="p">}</span></code></pre></div>
<h3 id="section-4">自定义控件</h3>
<p>这里用到的自定义有两个，第一个是NEXT的<code>Button</code>。仔细观察一下原型图，Button主要有两个特点：</p>
<ul>
  <li>渐出动画是在PopUpView之前就开始，而且是独立渐出</li>
  <li>Button的背景色是一种渐变色</li>
</ul>
<p>对于第一个动效，只需要在PopUpView启动退出动画之前，先执行Button内部的退出动画。动画无论退出还是出现都是类似的<code>CGAffineTransformMakeScale</code>效果，无需讲述。</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1">#pragma mark - Animation</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span> <span class="n">pressAnimation</span> <span class="p">{</span>
    <span class="no">NSLog</span><span class="p">(</span><span class="err">@</span><span class="s2">&quot;click&quot;</span><span class="p">);</span>
    <span class="nb">self</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="no">CGAffineTransformMakeScale</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="o">[</span><span class="no">UIView</span> <span class="ss">animateWithDuration</span><span class="p">:</span> <span class="mi">0</span><span class="o">.</span><span class="mi">6</span>
                          <span class="ss">delay</span><span class="p">:</span> <span class="mi">0</span>
                        <span class="ss">options</span><span class="p">:</span> <span class="no">UIViewAnimationOptionCurveEaseInOut</span>
                     <span class="ss">animations</span><span class="p">:</span> <span class="o">^</span><span class="p">{</span>
                         <span class="nb">self</span><span class="o">.</span><span class="n">transform</span> <span class="o">=</span> <span class="no">CGAffineTransformMakeScale</span><span class="p">(</span><span class="mi">0</span><span class="o">.</span><span class="mo">01</span><span class="p">,</span> <span class="mi">0</span><span class="o">.</span><span class="mo">01</span><span class="p">);</span>
                     <span class="p">}</span>
                     <span class="ss">completion</span><span class="p">:</span> <span class="o">^</span><span class="p">(</span><span class="no">BOOL</span> <span class="n">finished</span><span class="p">)</span> <span class="p">{</span>
                         <span class="o">[</span><span class="nb">self</span> <span class="n">removeFromSuperview</span><span class="o">]</span><span class="p">;</span>
                     <span class="p">}</span><span class="o">]</span><span class="p">;</span>
    <span class="o">[[</span><span class="no">NSNotificationCenter</span> <span class="n">defaultCenter</span><span class="o">]</span> <span class="ss">postNotificationName</span><span class="p">:</span> <span class="err">@</span><span class="s2">&quot;NEXT_Button&quot;</span> <span class="ss">object</span><span class="p">:</span> <span class="kp">nil</span><span class="o">]</span><span class="p">;</span>
<span class="p">}</span></code></pre></div>
<p>渐变色的处理我们可以使用<code>CAGradientLayer</code>这个类。<code>CAGradientLayer</code>是用来生成两种或更多颜色平滑渐变，使用改类的好处在于绘制时使用了硬件加速（<a href="https://developer.apple.com/reference/quartzcore/cagradientlayer">官方文档</a>）。我们只要依次写出各个关键点，就可以确定颜色的一个渐变方向。直接看代码，很容易就能看懂。</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1">#pragma mark - Set Color</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span> <span class="n">setColor</span> <span class="p">{</span>
    <span class="no">CAGradientLayer</span> <span class="o">*</span><span class="n">gradientLayer</span> <span class="o">=</span> <span class="o">[</span><span class="no">CAGradientLayer</span> <span class="n">layer</span><span class="o">]</span><span class="p">;</span>
    <span class="n">gradientLayer</span><span class="o">.</span><span class="n">frame</span> <span class="o">=</span> <span class="nb">self</span><span class="o">.</span><span class="n">bounds</span><span class="p">;</span>
    <span class="n">gradientLayer</span><span class="o">.</span><span class="n">locations</span> <span class="o">=</span> <span class="err">@</span><span class="o">[</span><span class="err">@</span><span class="mi">0</span><span class="o">.</span><span class="mi">3</span><span class="p">,</span> <span class="err">@</span><span class="mi">0</span><span class="o">.</span><span class="mi">8</span><span class="o">]</span><span class="p">;</span>
    <span class="n">gradientLayer</span><span class="o">.</span><span class="n">colors</span> <span class="o">=</span> <span class="err">@</span><span class="o">[</span><span class="p">(</span><span class="n">__bridge</span> <span class="nb">id</span><span class="p">)</span><span class="o">[</span><span class="no">UIColor</span> <span class="ss">colorWithRed</span><span class="p">:</span> <span class="mi">56</span> <span class="o">/</span> <span class="mi">255</span><span class="o">.</span><span class="n">f</span> <span class="ss">green</span><span class="p">:</span> <span class="mi">195</span> <span class="o">/</span> <span class="mi">255</span><span class="o">.</span><span class="n">f</span> <span class="ss">blue</span><span class="p">:</span> <span class="mi">227</span> <span class="o">/</span> <span class="mi">255</span><span class="o">.</span><span class="n">f</span> <span class="ss">alpha</span><span class="p">:</span> <span class="mi">1</span><span class="o">].</span><span class="n">CGColor</span><span class="p">,</span>
                             <span class="p">(</span><span class="n">__bridge</span> <span class="nb">id</span><span class="p">)</span><span class="o">[</span><span class="no">UIColor</span> <span class="ss">colorWithRed</span><span class="p">:</span> <span class="mi">16</span> <span class="o">/</span> <span class="mi">255</span><span class="o">.</span><span class="n">f</span> <span class="ss">green</span><span class="p">:</span> <span class="mi">156</span> <span class="o">/</span> <span class="mi">255</span><span class="o">.</span><span class="n">f</span> <span class="ss">blue</span><span class="p">:</span> <span class="mi">197</span> <span class="o">/</span> <span class="mi">255</span><span class="o">.</span><span class="n">f</span> <span class="ss">alpha</span><span class="p">:</span> <span class="mi">1</span><span class="o">].</span><span class="n">CGColor</span><span class="o">]</span><span class="p">;</span>
    <span class="n">gradientLayer</span><span class="o">.</span><span class="n">startPoint</span> <span class="o">=</span> <span class="no">CGPointMake</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">gradientLayer</span><span class="o">.</span><span class="n">endPoint</span> <span class="o">=</span> <span class="no">CGPointMake</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">layer</span> <span class="ss">addSublayer</span><span class="p">:</span> <span class="n">gradientLayer</span><span class="o">]</span><span class="p">;</span>
<span class="p">}</span></code></pre></div>
<p>我们最后来说说自定义的<code>TextField</code>，<code>TextField</code>我们仅仅是在下方增加了一个类似于进度条的动画。具体的逻辑是这样，当我们手势响应一个<code>TextField</code>之后，我们就会启动动画，让进度条滑动到定点位置。而当我们退出响应该TextField的时候，先要检查text部分是否为空，然后在决定进度条是否要保存状态。先给出代码，解释一下。</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1">#pragma mark - UITextFieldDelegate</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span><span class="ss">textFieldDidBeginEditing</span><span class="p">:</span> <span class="p">(</span><span class="no">UITextField</span> <span class="o">*</span><span class="p">)</span><span class="n">textField</span> <span class="p">{</span>
    <span class="sr">//</span> <span class="err">确定动画类型</span>
    <span class="no">CABasicAnimation</span> <span class="o">*</span><span class="n">basic</span> <span class="o">=</span> <span class="o">[</span><span class="no">CABasicAnimation</span> <span class="ss">animationWithKeyPath</span><span class="p">:</span> <span class="err">@</span><span class="s2">&quot;transform.scale.x&quot;</span><span class="o">]</span><span class="p">;</span>
    <span class="sr">//</span> <span class="err">确定锚点</span>
    <span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">progressLine</span><span class="o">.</span><span class="n">layer</span> <span class="ss">setAnchorPoint</span><span class="p">:</span> <span class="no">CGPointMake</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="o">.</span><span class="mi">5</span><span class="p">)</span><span class="o">]</span><span class="p">;</span>
    <span class="sr">//</span> <span class="err">持续时间</span>
    <span class="n">basic</span><span class="o">.</span><span class="n">duration</span> <span class="o">=</span> <span class="mi">0</span><span class="o">.</span><span class="mi">3</span><span class="p">;</span>
    <span class="sr">//</span> <span class="err">重复次数</span>
    <span class="n">basic</span><span class="o">.</span><span class="n">repeatCount</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="sr">//</span> <span class="err">结束后是否删除</span>
    <span class="n">basic</span><span class="o">.</span><span class="n">removedOnCompletion</span> <span class="o">=</span> <span class="no">NO</span><span class="p">;</span>
    <span class="sr">//</span> <span class="err">状态点数值</span>
    <span class="n">basic</span><span class="o">.</span><span class="n">fromValue</span> <span class="o">=</span> <span class="o">[</span><span class="no">NSNumber</span> <span class="ss">numberWithFloat</span><span class="p">:</span> <span class="mi">1</span><span class="o">]</span><span class="p">;</span>
    <span class="n">basic</span><span class="o">.</span><span class="n">toValue</span> <span class="o">=</span> <span class="o">[</span><span class="no">NSNumber</span> <span class="ss">numberWithFloat</span><span class="p">:</span> <span class="mi">280</span><span class="o">]</span><span class="p">;</span>
    <span class="sr">//</span> <span class="err">完成时保存状态</span>
    <span class="n">basic</span><span class="o">.</span><span class="n">fillMode</span> <span class="o">=</span> <span class="n">kCAFillModeForwards</span><span class="p">;</span>
    <span class="sr">//</span> <span class="err">增加缓动函数</span>
    <span class="n">basic</span><span class="o">.</span><span class="n">timingFunction</span> <span class="o">=</span> <span class="o">[</span><span class="no">CAMediaTimingFunction</span> <span class="ss">functionWithName</span><span class="p">:</span> <span class="n">kCAMediaTimingFunctionEaseIn</span><span class="o">]</span><span class="p">;</span>
    <span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">progressLine</span><span class="o">.</span><span class="n">layer</span> <span class="ss">addAnimation</span><span class="p">:</span> <span class="n">basic</span> <span class="ss">forKey</span><span class="p">:</span> <span class="kp">nil</span><span class="o">]</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">-</span> <span class="p">(</span><span class="n">void</span><span class="p">)</span><span class="ss">textFieldDidEndEditing</span><span class="p">:(</span><span class="no">UITextField</span> <span class="o">*</span><span class="p">)</span><span class="n">textField</span><span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">textField</span><span class="o">.</span><span class="n">text</span> <span class="ss">isEqualToString</span><span class="p">:</span> <span class="err">@</span><span class="s2">&quot;&quot;</span><span class="o">]</span><span class="p">)</span> <span class="p">{</span>
        <span class="no">CABasicAnimation</span> <span class="o">*</span><span class="n">basic</span> <span class="o">=</span> <span class="o">[</span><span class="no">CABasicAnimation</span> <span class="ss">animationWithKeyPath</span><span class="p">:</span> <span class="err">@</span><span class="s2">&quot;transform.scale.x&quot;</span><span class="o">]</span><span class="p">;</span>
        <span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">progressLine</span><span class="o">.</span><span class="n">layer</span> <span class="ss">setAnchorPoint</span><span class="p">:</span> <span class="no">CGPointMake</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="o">.</span><span class="mi">5</span><span class="p">)</span><span class="o">]</span><span class="p">;</span>
        <span class="n">basic</span><span class="o">.</span><span class="n">duration</span> <span class="o">=</span> <span class="mi">0</span><span class="o">.</span><span class="mi">3</span><span class="p">;</span>
        <span class="n">basic</span><span class="o">.</span><span class="n">repeatCount</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="n">basic</span><span class="o">.</span><span class="n">removedOnCompletion</span> <span class="o">=</span> <span class="no">NO</span><span class="p">;</span>
        <span class="n">basic</span><span class="o">.</span><span class="n">fromValue</span> <span class="o">=</span> <span class="o">[</span><span class="no">NSNumber</span> <span class="ss">numberWithFloat</span><span class="p">:</span> <span class="mi">280</span><span class="o">]</span><span class="p">;</span>
        <span class="n">basic</span><span class="o">.</span><span class="n">toValue</span> <span class="o">=</span> <span class="o">[</span><span class="no">NSNumber</span> <span class="ss">numberWithFloat</span><span class="p">:</span> <span class="mi">1</span><span class="o">]</span><span class="p">;</span>
        <span class="n">basic</span><span class="o">.</span><span class="n">fillMode</span> <span class="o">=</span> <span class="n">kCAFillModeForwards</span><span class="p">;</span>
        <span class="n">basic</span><span class="o">.</span><span class="n">timingFunction</span> <span class="o">=</span> <span class="o">[</span><span class="no">CAMediaTimingFunction</span> <span class="ss">functionWithName</span><span class="p">:</span> <span class="n">kCAMediaTimingFunctionEaseIn</span><span class="o">]</span><span class="p">;</span>
        <span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">progressLine</span><span class="o">.</span><span class="n">layer</span> <span class="ss">addAnimation</span><span class="p">:</span> <span class="n">basic</span> <span class="ss">forKey</span><span class="p">:</span> <span class="kp">nil</span><span class="o">]</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>这里我们不在对View层进行动画，而是改用<code>CABasicAnimation</code>。好处仍旧是硬件加速。这里我们特别要注意一个地方。刚开始接触<code>CABasicAnimation</code>的时候，可能不太理解<code>fromValue</code>和<code>toValue</code>。这两个数值既不反应屏幕坐标，也不表示像素数。它的意思是起始尺寸数值的整数倍数。也就是说，这里我们假设进度条的长度为x，则该动画的过程就是把进度条长度线性的从x增长到280x，这里也就反应了一个问题，我们在<strong>设定进度条初值的时候不能设置成0</strong>。</p>
<p><img src="http://7xwh85.com1.z0.glb.clouddn.com/2016-06-18-img_3.gif" width="240px" /></p>
<h2 id="section-5">结束语</h2>
<p>大体上，整个卡片登录界面的实现思路就是这样，最后再次感谢原型图作者。在进行动画制作之后，强烈建议读者去学习<a href="https://www.gitbook.com/book/zsisme/ios-/details">《iOS Core Animation: Advanced Techniques》</a>这本书，之后会对Core Animation会有更深层的认识。</p>
<hr />
<p><a href="https://github.com/dgytdhy/DGPopUpViewController">DGPopUpViewController repo</a></p>
  <footer class="post-footer">
    <section class="author">
      <h4>Desgard_Duan</h4>
      <p>I write many code to write less code.💻</p>
    </section>
<aside class="share">
  <h4>Share this.</h4>
  <a href="http://twitter.com/share?text=《The Card Interface For Signing Up》 -- Guardia · 瓜地&amp;url=https://www.desgard.com/The-Card-Interface-For-Signing-Up/"
  onclick="window.open(this.href, 'twitter-share', 'width=550,height=235');return false;">
    <i class="fa fa-twitter-square"></i>
  </a>
  <a href="http://v.t.sina.com.cn/share/share.php?url=https://www.desgard.com/The-Card-Interface-For-Signing-Up/&amp;title=《The Card Interface For Signing Up》 —— Guardia · 瓜地" onclick="window.open(this.href, 'twitter-share', 'width=550,height=235');return false;">
    <i class="fa fa-weibo"></i>
  </a>
</aside>
      <hr>
<aside id="comments" class="disqus">
  <div id="container"></div>
  <!-- <link rel="stylesheet" href="/assets/css/gitment.css">
  <script src="https://imsun.github.io/gitment/dist/gitment.browser.js"></script>
  <script>
  var gitment = new Gitment({
    id: "https://www.desgard.com/The-Card-Interface-For-Signing-Up/", 
    owner: 'Desgard',
    repo: 'desgard.github.com',
    oauth: {
      client_id: 'e2612df42f3f2a83e71c',
      client_secret: 'b53e85b314bb24a6d06773e48bbb62a4de3b8b3a',
    },
  })
  gitment.render('container')
  </script> -->
<link rel="stylesheet" href="/assets/css/gitalk.css">
<script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
<div id='gitalk-container'></div>
<script>
    const gitalk = new Gitalk({
        id: "https://www.desgard.com/The-Card-Interface-For-Signing-Up/", 
        clientID: 'e2612df42f3f2a83e71c',
        clientSecret: 'b53e85b314bb24a6d06773e48bbb62a4de3b8b3a',
        repo: 'desgard.github.com',
        owner: 'Desgard',
        admin: ['Desgard'],
        // facebook-like distraction free mode
        distractionFreeMode: false
    })
    gitalk.render('gitalk-container')
</script>
</aside>
  </footer>
</article>
    </main>
<footer class="footer">
  <div class="container">
    <ul class="icons">
      <li>
        <a href="https://github.com/desgard" class="icon-github" target="_blank">
          <i class="fa fa-github"></i>
        </a>
      </li>
      <li>
        <a href="https://www.facebook.com/desgard.duan" class="icon-facebook" target="_blank">
          <i class="fa fa-facebook"></i>
        </a>
      </li>
      <li>
        <a href="https://twitter.com/Desgard_Duan" class="icon-twitter" target="_blank">
          <i class="fa fa-twitter"></i>
        </a>
      </li>
      <li>
        <a href="https://stackoverflow.com/users/6119149/desgard-duan" class="icon-github" target="_blank">
          <i class="fa fa-stack-overflow"></i>
        </a>
      </li>
      <li>
        <a href="https://weibo.com/desgard" class="icon-instagram" target="_blank">
          <i class="fa fa-weibo"></i>
        </a>
      </li>
    </ul>
    <p>
      <q>I write many code to write less code.💻</q>
      <small>– Gua</small>
    </p>
    <small class="clearfix">
      Powered by <a href="http://jekyllrb.com" target="_blank">Jekyll</a> • <a href="https://github.com/desgard" target="_blank">Open source <i class="fa fa-heart"></i></a>
    </small>
  </div>
</footer>
<a class="scroll-up fa fa-chevron-up bounce" href="#" data-position="0"></a>
<div id="modalSearch" class="modal">
  <div class="modal__overlay"></div>
  <div class="modal__content">
    <a href="#!" class="modal-close" data-modal-close>&times;</a>
    <div class="search-container">
      <input type="text" id="search-input" placeholder="Search articles">
      <ul id="results-container"></ul>
    </div>
  </div>
</div>
    <script src="/assets/main-52d417e8a6ff9f5b168386d37c96338a.js"></script>
  </body>
  <script>
    var link = "" ;
    var os = function() {  
      var ua = navigator.userAgent,  
      isWindowsPhone = /(?:Windows Phone)/.test(ua),  
      isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,   
      isAndroid = /(?:Android)/.test(ua),   
      isFireFox = /(?:Firefox)/.test(ua),   
      isChrome = /(?:Chrome|CriOS)/.test(ua),  
      isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)),  
      isPhone = /(?:iPhone)/.test(ua) && !isTablet,  
      isPc = !isPhone && !isAndroid && !isSymbian;  
      return {  
        isTablet: isTablet,  
        isPhone: isPhone,  
        isAndroid : isAndroid,  
        isPc : isPc  
      };  
    }();  
    if (link.length > 0) {
      if (os.isAndroid || os.isPhone) {
        location.replace(link);
      }
    }
  </script>
</html>